#!/usr/bin/env python3

import socket
import time
import select


def event_loop(handlers):
    while True:
        wants_recv = [h for h in handlers if h.wants_to_receive()]
        wants_send = [h for h in handlers if h.wants_to_send()]
        can_recv, can_send, _ = select.select(wants_recv, wants_send, [])
        for h in can_recv:
            h.handle_receive()
            print('{} handle receive'.format(h.name))
        for h in can_send:
            h.handle_send()


class EventHandler:
    def fileno(self):
        'Return the associated file descriptor'
        raise NotImplemented('must implement')

    def wants_to_receive(self):
        'Return True if receiving is allowed'
        return False

    def handle_receive(self):
        'Perform the receive operation'
        pass

    def wants_to_send(self):
        'Return True if sending is requested'
        return False

    def handle_send(self):
        'Send outgoing data'
        pass


class UDPServer(EventHandler):

    def __init__(self, address, name = ''):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.sock.bind(address)
        self.name = name

    def fileno(self):
        return self.sock.fileno()

    def wants_to_receive(self):
        return True


class UDPTimeServer(UDPServer):

    def handle_receive(self):
        msg, addr = self.sock.recvfrom(1)
        self.sock.sendto(time.ctime().encode('ascii'), addr)


class UDPEchoServer(UDPServer):

    def handle_receive(self):
        msg, addr = self.sock.recvfrom(8192)
        self.sock.sendto(msg, addr)


if __name__ == '__main__':
    handlers = [UDPTimeServer(('', 14000), 'TimeServer'), UDPEchoServer(('', 15000), 'EchoServer')]
    event_loop(handlers)


# class TCPServer(EventHandler):
#     def __init__(self, address, client_handler, handler_list):
#         self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#         self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
#         self.sock.bind(address)
#         self.sock.listen(1)
#         self.client_handler = client_handler
#         self.handler_list = handler_list

#     def fileno(self):
#         return self.sock.fileno()

#     def wants_to_receive(self):
#         return True

#     def handle_receive(self):
#         client, addr = self.sock.accept()
#         # Add the client to the event loop's handler list
#         self.handler_list.append(self.client_handler(client, self.handler_list))

# class TCPClient(EventHandler):
#     def __init__(self, sock, handler_list):
#         self.sock = sock
#         self.handler_list = handler_list
#         self.outgoing = bytearray()

#     def fileno(self):
#         return self.sock.fileno()

#     def close(self):
#         self.sock.close()
#         # Remove myself from the event loop's handler list
#         self.handler_list.remove(self)

#     def wants_to_send(self):
#         return True if self.outgoing else False

#     def handle_send(self):
#         nsent = self.sock.send(self.outgoing)
#         self.outgoing = self.outgoing[nsent:]

# class TCPEchoClient(TCPClient):
#     def wants_to_receive(self):
#         return True

#     def handle_receive(self):
#         data = self.sock.recv(8192)
#         if not data:
#             self.close()
#         else:
#             self.outgoing.extend(data)

# if __name__ == '__main__':
#    handlers = []
#    handlers.append(TCPServer(('',16000), TCPEchoClient, handlers))
#    event_loop(handlers)
